﻿using System;
using System.Collections.Generic;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml.Linq;
using BlogEngine.Core.Providers;

namespace BlogEngine.SQLServer
{
    internal static class Utils
    {
        private const string blogIdTag = "currentBlogId";

        // we need both the blog and the membership XMLMappingSource objects because it is conceivable that users will have different
        //    values for things like tablePrefix and schema defined in the web.config elements referencing the provider.
        internal static XmlMappingSource blogMappingSource;
        internal static XmlMappingSource membershipMappingSource;
        internal static BlogData.BlogDataContext getNewBlogContext(string connString, string tablePrefix, string schema)
        {
            return new BlogData.BlogDataContext(connString, getBlogSource(tablePrefix, schema));
        }

        internal static BlogData.BlogDataContext getNewMembershipContext(string connString, string tablePrefix, string schema)
        {
            return new BlogData.BlogDataContext(connString, getMembershipSource(tablePrefix, schema));
        }

        private static Guid blogId;

        /// <summary>
        /// Used to produce the BlogId for a request in a multi-blog setup.
        /// </summary>
        /// <returns></returns>
        internal static Guid GetBlogId()
        {
            if (blogId == Guid.Empty)
            {
                Uri url = HttpContext.Current.Request.Url;

                SqlBlogProvider provider = (SqlBlogProvider)BlogService.Provider;
                using (BlogData.BlogDataContext context = getNewBlogContext(provider.connString, provider.tablePrefix, provider.schema))
                {
                    var blogs = (from blog in context.Blogs
                             select blog).ToList();

                    var selected = blogs.Where(b => url.Host.EndsWith(b.Host));
                    selected = selected.Where(b => url.PathAndQuery.StartsWith(b.Path == null ? string.Empty : b.Path));
                    selected = selected.Where(b => !b.Port.HasValue || b.Port.Value == url.Port);

                    if (selected.Count() <= 0)
                    {
                        selected = blogs.Where(b => b.IsDefault ?? false == true);
                    }

                    blogId = selected
                        .OrderByDescending(b => b.Port ?? 0)
                        .OrderBy(b => (b.Path == null ? string.Empty : b.Path).Length).Select(b => b.BlogId).FirstOrDefault();
                }
            }


            return blogId;
        }

        private static XmlMappingSource getMembershipSource(string tablePrefix, string schema)
        {
            if (membershipMappingSource == null)
            {
                membershipMappingSource = createSource(tablePrefix, schema);
            }
            return membershipMappingSource;
        }

        private static XmlMappingSource getBlogSource(string tablePrefix, string schema)
        {
            if (blogMappingSource == null)
            {
                blogMappingSource = createSource(tablePrefix, schema);
            }
            return blogMappingSource;
        }

        private static XmlMappingSource createSource(string tablePrefix, string schema)
        {
            XDocument doc = XDocument.Parse(Properties.Resources.BlogData);
            XNamespace ns = "http://schemas.microsoft.com/linqtosql/mapping/2007";
            if (!string.IsNullOrEmpty(tablePrefix) || !string.IsNullOrEmpty(schema))
            {
                foreach (XElement table in doc.Descendants(ns + "Table"))
                {
                    table.Attribute("Name").Value = table.Attribute("Name").Value.Replace("dbo.", string.Format("{0}.{1}", schema, tablePrefix));
                }
            }
            return XmlMappingSource.FromXml(doc.ToString());
        }
    }
}
